Skip to content

feat(plugin-sentry): add plugin for sentry#689

Closed
orionmiz wants to merge 11 commits intomainfrom
edward_karrot/fix-plugin-sentry
Closed

feat(plugin-sentry): add plugin for sentry#689
orionmiz wants to merge 11 commits intomainfrom
edward_karrot/fix-plugin-sentry

Conversation

@orionmiz
Copy link
Copy Markdown
Collaborator

@orionmiz orionmiz commented Mar 30, 2026

This PR continues the work from #547. Thanks to @ysh4296 for the initial implementation.

plugin-sentry (Issue from #520)

Stackflow has a unique screen handling with "Activity."
Currently, Sentry doesn't support tracing for this mechanism,
so we created a dedicated plugin.

This PR contains a plugin that provides:

  • Tracing page load events
  • Tracing activity changes (push, pop, replace)
  • Tracing step changes (stepPush, stepPop, stepReplace)
  • Navigation breadcrumbs for error context
  • Activity/step params included in spans and breadcrumbs

Changes from #547

  • Decouple Sentry initialization from the plugin — users call Sentry.init() themselves and add stackflowBrowserTracingIntegration() to their integrations
  • Move @sentry/browser, @sentry/core, @stackflow/core to peerDependencies
  • Remove @sentry/types (deprecated in v8) and WINDOW internal API usage
  • Add breadcrumb recording for all navigation events
  • Include activity params and step params in span attributes and breadcrumb data
  • Add step-level navigation tracing (onStepPushed, onStepPopped, onStepReplaced)
  • Fix version field typo (0,0,00.0.0)
  • Upgrade Sentry packages to v10

How to use

import * as Sentry from "@sentry/browser";
import { stackflowBrowserTracingIntegration, sentryPlugin } from "@stackflow/plugin-sentry";

// 1. Initialize Sentry separately
Sentry.init({
  dsn: "https://example-dsn-key",
  integrations: [stackflowBrowserTracingIntegration()],
  tracesSampleRate: 1.0,
});

// 2. Add the plugin to stackflow
const { Stack } = stackflow({
  config,
  components: { Main, Article },
  plugins: [sentryPlugin()],
});

ysh4296 and others added 8 commits December 16, 2024 15:47
- Separate Sentry init from plugin (user inits Sentry, plugin handles navigation spans)
- Move @sentry/browser, @sentry/core, @stackflow/core to peerDependencies
- Replace internal WINDOW import with direct window check
- Remove unsafe integrations type cast
- Extract shared navigation span helper and add breadcrumb support
- Upgrade devDependencies to @sentry/browser@10, @sentry/core@10
- Fix version field typo (commas to dots)
- Update README with two-step setup guide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 30, 2026

🦋 Changeset detected

Latest commit: 3a116b3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@stackflow/plugin-sentry Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Mar 30, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
stackflow-docs 3a116b3 Mar 30 2026, 10:08 AM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 30, 2026

  • @stackflow/demo

    yarn add https://pkg.pr.new/daangn/stackflow/@stackflow/plugin-sentry@689.tgz
    

commit: 3a116b3

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bfad88a4-e4b4-4d02-b471-7e0b2a6f3bac

📥 Commits

Reviewing files that changed from the base of the PR and between 04686f5 and 3a116b3.

📒 Files selected for processing (2)
  • .changeset/fix-plugin-sentry.md
  • extensions/plugin-sentry/README.md
✅ Files skipped from review due to trivial changes (2)
  • .changeset/fix-plugin-sentry.md
  • extensions/plugin-sentry/README.md

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a Sentry plugin that records navigation spans and breadcrumbs for push/pop/replace and step events, plus an optional browser-tracing integration that can create page-load spans.
  • Documentation

    • Added setup and usage instructions for the plugin and tracing integration.
  • Bug Fixes

    • Plugin no longer performs implicit Sentry initialization; tracing integration exposes explicit setup options.
  • Chores

    • Packaging, build, and manifest entries added to publish and register the new plugin.

Walkthrough

Adds a new Stackflow Sentry extension under extensions/plugin-sentry/ (plugin, Sentry integration wrapper, build/config, README, package manifest, changeset) and registers Sentry-related packages and the workspace package in the Yarn PnP runtime graph.

Changes

Cohort / File(s) Summary
Build & Manifest
extensions/plugin-sentry/package.json, extensions/plugin-sentry/esbuild.config.js, extensions/plugin-sentry/tsconfig.json
New package manifest with exports, entrypoints, scripts, peer/dev deps; esbuild config producing CJS+ESM builds (watch support); TypeScript config (src → dist).
Source & Exports
extensions/plugin-sentry/src/index.ts, extensions/plugin-sentry/src/sentryPlugin.ts, extensions/plugin-sentry/src/integration.ts
New public exports: sentryPlugin() (registers navigation/step event handlers to start Sentry spans and add breadcrumbs) and stackflowBrowserTracingIntegration() (wraps Sentry browserTracingIntegration to control page-load span behavior).
Docs & Changeset
extensions/plugin-sentry/README.md, .changeset/fix-plugin-sentry.md
Added README with setup steps and a changeset declaring a minor version bump; notes decoupled Sentry initialization from the plugin.
Runtime state
.pnp.cjs
Yarn PnP runtime entries updated to include workspace mapping for @stackflow/plugin-sentry and multiple Sentry-related packages (@sentry/browser, @sentry/core, @sentry-internal/*) resolved at v10.46.0.

Sequence Diagram(s)

sequenceDiagram
    participant Activity as Stackflow Activity
    participant Plugin as Sentry Plugin
    participant Sentry as Sentry SDK
    participant Browser as Browser

    Activity->>Plugin: emit onPushed/onPopped/onReplaced (action, activity, params)
    Plugin->>Sentry: Sentry.getClient() (guard)
    alt client available
        Plugin->>Sentry: start navigation span ("<action> <activity>") with attrs (op, origin, source, stackflow.*)
        Plugin->>Sentry: addBreadcrumb(category:"navigation", message:"<action> <activity>", data: params)
    else no client
        Plugin-->>Activity: skip span/breadcrumb
    end

    Browser->>Sentry: stackflowBrowserTracingIntegration.afterAllSetup()
    alt instrumentPageLoad enabled & browser
        Sentry->>Sentry: start page-load span (name=window.location.pathname, attrs: op=pageload, origin=auto.pageload.stackflow)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a Sentry plugin for Stackflow. It directly relates to the primary objective of the PR.
Description check ✅ Passed The description comprehensively explains the plugin's purpose, features, implementation changes from prior work, and provides clear usage examples related to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch edward_karrot/fix-plugin-sentry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
extensions/plugin-sentry/esbuild.config.js (1)

29-29: Log the build error before exiting for faster failure diagnosis.

At Line 29, the catch block drops error details, which makes CI/local troubleshooting harder.

🔧 Suggested improvement
-]).catch(() => process.exit(1));
+]).catch((error) => {
+  console.error(error);
+  process.exit(1);
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/plugin-sentry/esbuild.config.js` at line 29, The current promise
rejection handler .catch(() => process.exit(1)) discards the error; update the
catch to accept the error (e.g., .catch((err) => { /* log */ })) and log the
error before exiting (for example call console.error or the project's logger
with a clear message like "Build failed" plus err) and then call process.exit(1)
so failures are visible in CI/local runs.
extensions/plugin-sentry/src/integration.ts (1)

33-33: Prefer normalized pageload names over raw pathname.

Using window.location.pathname directly can create high-cardinality transaction names (and may carry IDs). A normalized route-style name is safer for aggregation.

♻️ Proposed refinement
+function normalizeTransactionPath(pathname: string): string {
+  return pathname
+    .replace(/\/\d+(?=\/|$)/g, "/:id")
+    .replace(
+      /\/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}(?=\/|$)/gi,
+      "/:id",
+    );
+}
+
 export function stackflowBrowserTracingIntegration(
   options: Parameters<typeof originalBrowserTracingIntegration>[0] = {},
 ) {
@@
       if (instrumentPageLoad && initialWindowLocation) {
         startBrowserTracingPageLoadSpan(client, {
-          name: initialWindowLocation.pathname,
+          name: normalizeTransactionPath(initialWindowLocation.pathname),
           attributes: {
             [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "pageload",
             [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.pageload.stackflow",
             [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
           },
         });
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/plugin-sentry/src/integration.ts` at line 33, The code uses
initialWindowLocation.pathname for transaction/route naming which can produce
high-cardinality and leak IDs; update the usage in integration.ts to normalize
the page load name (e.g., map or sanitize initialWindowLocation.pathname via a
normalizeRoute or sanitizePath function) before assigning to the transaction
name, replacing direct references to initialWindowLocation.pathname; ensure the
normalizer strips or tokenizes dynamic segments (IDs, UUIDs, numeric params) and
returns a stable route-style string for Sentry aggregation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/plugin-sentry/package.json`:
- Line 30: The dev script in package.json uses "yarn build:js --watch && yarn
build:dts --watch" so the second watcher never starts; change the dev script to
run both watchers concurrently (e.g., use the "concurrently" tool to run "yarn
build:js --watch" and "yarn build:dts --watch" in parallel) and add
"concurrently" to devDependencies if it's not already installed so both watchers
(build:js and build:dts) run at the same time.
- Around line 33-34: The code currently depends on the unstable internal hook
browserTracingIntegration().afterAllSetup (used in integration.ts) while
package.json allows ">=8.0.0" for `@sentry/browser` and `@sentry/core`; either
refactor to remove the internal hook by wiring Sentry using the public APIs
(replace browserTracingIntegration().afterAllSetup usage with calls to
startBrowserTracingNavigationSpan and startBrowserTracingPageLoadSpan in the
appropriate initialization flow) or lock the peerDependency range to a tested
major (e.g., change ">=8.0.0" to "^8.0.0" or "^8") to prevent unexpected
breaking changes. Ensure you update integration.ts to reference only
startBrowserTracingNavigationSpan and startBrowserTracingPageLoadSpan if you
choose the refactor, or update package.json ranges consistently if you choose
pinning.

---

Nitpick comments:
In `@extensions/plugin-sentry/esbuild.config.js`:
- Line 29: The current promise rejection handler .catch(() => process.exit(1))
discards the error; update the catch to accept the error (e.g., .catch((err) =>
{ /* log */ })) and log the error before exiting (for example call console.error
or the project's logger with a clear message like "Build failed" plus err) and
then call process.exit(1) so failures are visible in CI/local runs.

In `@extensions/plugin-sentry/src/integration.ts`:
- Line 33: The code uses initialWindowLocation.pathname for transaction/route
naming which can produce high-cardinality and leak IDs; update the usage in
integration.ts to normalize the page load name (e.g., map or sanitize
initialWindowLocation.pathname via a normalizeRoute or sanitizePath function)
before assigning to the transaction name, replacing direct references to
initialWindowLocation.pathname; ensure the normalizer strips or tokenizes
dynamic segments (IDs, UUIDs, numeric params) and returns a stable route-style
string for Sentry aggregation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3792b7af-fc17-4567-85e4-7f8821d1d63d

📥 Commits

Reviewing files that changed from the base of the PR and between c92a1c4 and 17c9a32.

⛔ Files ignored due to path filters (7)
  • .yarn/cache/@sentry-browser-npm-10.46.0-91e2f4dcc5-f447c01f96.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/@sentry-core-npm-10.46.0-8ff3972576-bbe823f9de.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/@sentry-internal-browser-utils-npm-10.46.0-c2bfafc8a9-6ae7c6cc8d.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/@sentry-internal-feedback-npm-10.46.0-94a0d30ebb-e6c0b1fa93.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/@sentry-internal-replay-canvas-npm-10.46.0-e0dee1cb26-0ddfacfc79.zip is excluded by !**/.yarn/**, !**/*.zip
  • .yarn/cache/@sentry-internal-replay-npm-10.46.0-21ab33d9b1-e7c3e9e880.zip is excluded by !**/.yarn/**, !**/*.zip
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • .changeset/fix-plugin-sentry.md
  • .pnp.cjs
  • extensions/plugin-sentry/README.md
  • extensions/plugin-sentry/esbuild.config.js
  • extensions/plugin-sentry/package.json
  • extensions/plugin-sentry/src/index.ts
  • extensions/plugin-sentry/src/integration.ts
  • extensions/plugin-sentry/src/sentryPlugin.ts
  • extensions/plugin-sentry/tsconfig.json

"build:dts": "tsc --emitDeclarationOnly",
"build:js": "node ./esbuild.config.js",
"clean": "rimraf dist",
"dev": "yarn build:js --watch && yarn build:dts --watch"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

dev script won’t run both watchers.

yarn build:js --watch is long-running, so yarn build:dts --watch never starts with &&.

🔧 Proposed fix
-    "dev": "yarn build:js --watch && yarn build:dts --watch"
+    "dev": "concurrently \"yarn build:js --watch\" \"yarn build:dts --watch\""
   "devDependencies": {
+    "concurrently": "^9.0.0",
     "@sentry/browser": "^10.46.0",
     "@sentry/core": "^10.46.0",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/plugin-sentry/package.json` at line 30, The dev script in
package.json uses "yarn build:js --watch && yarn build:dts --watch" so the
second watcher never starts; change the dev script to run both watchers
concurrently (e.g., use the "concurrently" tool to run "yarn build:js --watch"
and "yarn build:dts --watch" in parallel) and add "concurrently" to
devDependencies if it's not already installed so both watchers (build:js and
build:dts) run at the same time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Mar 30, 2026

Deploying stackflow-demo with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3a116b3
Status:🚫  Build failed.

View logs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
extensions/plugin-sentry/src/sentryPlugin.ts (1)

64-103: Correct implementation matching Stackflow's Effect types.

The hook implementations correctly match the Effect type definitions:

  • Activity-level hooks access effect.activity
  • onStepPushed/onStepReplaced correctly merge effect.step.params
  • onStepPopped correctly does not access step (per Effect.ts, STEP_POPPED has no step field)

The repeated call pattern could optionally be consolidated into a single helper, but the current explicit form is clear.

♻️ Optional: Extract common tracing helper
+function traceNavigation(
+  action: NavigationAction,
+  activityName: string,
+  params: Record<string, string | undefined>,
+): void {
+  startNavigationSpan(action, activityName, params);
+  addNavigationBreadcrumb(action, activityName, params);
+}
+
 export function sentryPlugin(): StackflowPlugin {
   return () => ({
     key: "plugin-sentry",
     onPushed({ effect }) {
       const { name, params } = effect.activity;
-      startNavigationSpan("push", name, params);
-      addNavigationBreadcrumb("push", name, params);
+      traceNavigation("push", name, params);
     },
     // ... apply similarly to other hooks
   });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/plugin-sentry/src/sentryPlugin.ts` around lines 64 - 103, The
implementations in sentryPlugin correctly follow Stackflow Effect types but you
can reduce repetition by extracting a small helper inside sentryPlugin that
takes (action: string, effect: Effect) or (action: string, name: string, params:
Record) and calls startNavigationSpan and addNavigationBreadcrumb; then replace
the bodies of onPushed, onPopped, onReplaced, onStepPushed, onStepPopped, and
onStepReplaced to invoke that helper (ensure step params are merged in
onStepPushed/onStepReplaced and not accessed in onStepPopped).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@extensions/plugin-sentry/src/sentryPlugin.ts`:
- Around line 64-103: The implementations in sentryPlugin correctly follow
Stackflow Effect types but you can reduce repetition by extracting a small
helper inside sentryPlugin that takes (action: string, effect: Effect) or
(action: string, name: string, params: Record) and calls startNavigationSpan and
addNavigationBreadcrumb; then replace the bodies of onPushed, onPopped,
onReplaced, onStepPushed, onStepPopped, and onStepReplaced to invoke that helper
(ensure step params are merged in onStepPushed/onStepReplaced and not accessed
in onStepPopped).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1bcad8f2-cc64-4004-aacc-5a45b3bc0fde

📥 Commits

Reviewing files that changed from the base of the PR and between 563a8a7 and 04686f5.

📒 Files selected for processing (1)
  • extensions/plugin-sentry/src/sentryPlugin.ts

…set to minor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@orionmiz orionmiz closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants